﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Windows.ApplicationModel;
using Windows.Data.Xml.Dom;
using Windows.Storage;

namespace TuanJuAPIManager.DealProviders
{
    public class DataManager
    {
        /// <summary>
        /// Get the deal data
        /// </summary>
        /// <param name="category">which category, if the category is all, then get all data</param>
        /// <param name="url">which url</param>
        /// <param name="dealCount">how many deal count need to get for one website, the null mean get all deals</param>
        /// <returns>all deal data</returns>
        public static async Task<IEnumerable<Deal>> GetDealDataAsync(Category category, string url, int? dealCount)
        {
            List<Deal> deals = new List<Deal>();
            Uri uri = new Uri(url);

            if (!Uri.CheckSchemeName(uri.Scheme))
            {
                throw new InvalidOperationException(string.Format("The url : '{0}' is invalid", url));
            }

            XmlDocument xDoc = await XmlDocument.LoadFromUriAsync(uri);
            XmlNodeList list = xDoc.SelectNodes(ConstContent.ProductDataXPath);
            IEnumerable<IXmlNode> iList = null;

            ////Get only one deal data
            if (dealCount != null)
            {
                iList = list.Take((int)dealCount);
            }

            foreach (IXmlNode item in iList == null ? list : iList)
            {
                Deal deal = new Deal();

                XmlNodeList parentNodeList = item.ParentNode.ParentNode.ChildNodes;
                foreach (IXmlNode xmlNode in parentNodeList)
                {
                    if (xmlNode.NodeName.Equals(ConstContent.LocProperty))
                    {
                        deal.UriLink = xmlNode.InnerText;
                    }
                }

                XmlNodeList xmlList = item.ChildNodes;

                foreach (IXmlNode node in xmlList)
                {
                    string value = node.InnerText;
                    switch (node.NodeName)
                    {
                        case ConstContent.WebsiteProperty:
                            deal.Website = value;
                            break;
                        case ConstContent.TitleProperty:
                            deal.Title = value;
                            break;
                        case ConstContent.CategoryProperty:
                        case ConstContent.CateProperty:
                        case ConstContent.SortProperty:
                            deal.Category = ConvertValueToCategory(value);
                            break;
                        case ConstContent.GidProperty:
                        case ConstContent.IdentifierProperty:
                            deal.Gid = value;
                            break;
                        case ConstContent.ImageProperty:
                            deal.Image = value;
                            break;
                        case ConstContent.ValueProperty:
                            deal.Value = ConvertValueToDouble(value);
                            break;
                        case ConstContent.PriceProperty:
                            deal.Price = ConvertValueToDouble(value);
                            break;
                        case ConstContent.RebateProperty:
                            deal.Discount = ConvertValueToDouble(value);
                            break;
                        case ConstContent.BoughtProperty:
                            deal.Bought = (int)ConvertValueToDouble(value);
                            break;
                        case ConstContent.StartTimeProperty:
                            deal.StartTime = ConvertValueToDateTime(value);
                            break;
                        case ConstContent.EndTimeProperty:
                            deal.EndTime = ConvertValueToDateTime(value);
                            break;
                        case ConstContent.DescriptionProperty:
                            deal.Description = value;
                            break;
                        case ConstContent.ShortTitleProperty:
                            deal.ShortTitle = value;
                            break;
                        case ConstContent.DetailsProperty:
                            deal.Details = value;
                            break;
                        default:
                            break;
                    }
                }

                deal.Discount = (int)(((float)deal.Price / (float)deal.Value) * 100);

                deal.ExpireTime = deal.EndTime.Subtract(deal.StartTime).Days;

                ////Get one category deal data
                if (category != Category.All)
                {
                    if (deal.Category == category)
                    {
                        deals.Add(deal);
                    }
                }
                else
                {
                    ////Get all deal data
                    deals.Add(deal);
                }
            }

            return deals;

        }

        /// <summary>
        /// async read the website data from xml file
        /// </summary>
        /// <returns>all website data</returns>
        public static async Task<Dictionary<string, string>> GetWebsiteAsync()
        {
            Dictionary<string, string> dictionary = new Dictionary<string, string>();

            XmlDocument xDoc = await GetFileValueAsync(ConstContent.AllUrlFile);

            XmlNodeList nodeList = xDoc.SelectNodes(ConstContent.UrlDataXPath);

            foreach (IXmlNode item in nodeList)
            {
                XmlElement xmlElment = (XmlElement)item;
                string attributeName = xmlElment.Attributes[0].LocalName.ToString();
                string value = xmlElment.GetAttribute(attributeName);
                dictionary.Add(attributeName, value);
            }

            return dictionary;
        }

        /// <summary>
        /// Get all city
        /// </summary>
        /// <returns>city</returns>
        public static async Task<Dictionary<string, City>> GetCityAsync()
        {
            Dictionary<string, City> cities = new Dictionary<string, City>();

            XmlDocument xDoc = await GetFileValueAsync(ConstContent.CityFile);

            XmlNodeList nodeList = xDoc.SelectNodes(ConstContent.CityDataXPath);

            foreach (IXmlNode item in nodeList)
            {
                string cityName = item.SelectSingleNode(ConstContent.CityNameProperty).InnerText;
                string cityNamePY = item.SelectSingleNode(ConstContent.ENCityNameProperty).InnerText;
                string cityId = item.SelectSingleNode(ConstContent.CityId).InnerText;
                string cityImage = item.SelectSingleNode("./Image").InnerText;

                City city = new City(cityId, cityName, cityNamePY, cityImage);

                cities.Add(cityName, city);
            }

            return cities;
        }

        /// <summary>
        /// read the value from xml file
        /// </summary>
        /// <param name="file">xml file path</param>
        /// <returns>one xmlDocument</returns>
        private static async Task<XmlDocument> GetFileValueAsync(string file)
        {
            StorageFolder storageFolder = Package.Current.InstalledLocation;
            StorageFile storageFile = await storageFolder.GetFileAsync(file);
            string s = await Windows.Storage.FileIO.ReadTextAsync(storageFile);

            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml(s);

            return xDoc;
        }

        /// <summary>
        /// Convert to string type to category type
        /// </summary>
        /// <param name="value">need to convert value</param>
        /// <returns>Category enum</returns>
        private static Category ConvertValueToCategory(string value)
        {
            Category objCategory;
            bool isValidCategory = Enum.TryParse(value, out objCategory);
            objCategory = isValidCategory ? objCategory : Category.其他;

            return objCategory;
        }

        /// <summary>
        /// Convert string type to Double type
        /// </summary>
        /// <param name="value">need to convert value</param>
        /// <returns>Double type value</returns>
        private static Double ConvertValueToDouble(string value)
        {
            return Double.Parse(value);
        }

        /// <summary>
        /// Convert string type to Datetime type
        /// </summary>
        // <param name="value">need to convert value</param>
        /// <returns>Datetime type value</returns>
        private static DateTime ConvertValueToDateTime(string value)
        {
            DateTime deafultTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            DateTime dateTime = deafultTime.AddSeconds(double.Parse(value)).ToLocalTime();

            return dateTime;
        }
    }
}
